//
// BisectionMethodTests.cpp
// Bisection Method Unit Tests.
//
// Author: Gabriel H. Barbuto (gbarbuto@dc.uba.ar)
//
#include <cmath>
#include <functional>
#include <vector>

#include <boost/test/unit_test.hpp>

#include "BisectionMethod.h"

BOOST_AUTO_TEST_SUITE(BisectionMethodTests)

BOOST_AUTO_TEST_CASE(ClassExample)
{
	double const EPSILON(0.0001);

	double const x0(0.4);
	double const x1(0.5);
	std::function<double(double)> const f([](double const &x) { return x * x + 2.0 * x - 1.0; });

	BisectionMethod method(f);

	double const x(method(x0, x1));

	BOOST_REQUIRE_CLOSE(0.41421356, x, EPSILON);
}

BOOST_AUTO_TEST_CASE(XSquaredFunction)
{
	double const EPSILON(0.0001);

	double const x0(-3.0);
	double const x1( 3.0);
	std::function<double(double)> const f([](double const &x) { return x * x; });

	BisectionMethod method(f);

	double const x(method(x0, x1));

	BOOST_REQUIRE_SMALL(x, EPSILON);
}

BOOST_AUTO_TEST_CASE(FailToFindRootOfXSquaredFunction)
{
	double const EPSILON(0.0001);

	double const x0(-3.0);
	double const x1( 4.0);
	std::function<double(double)> const f([](double const &x) { return x * x; });

	BisectionMethod method(f);

	double const x(method(x0, x1));

	BOOST_REQUIRE_CLOSE(4.0, x, EPSILON);
}

BOOST_AUTO_TEST_CASE(XCubicFunction)
{
	double const EPSILON(0.0001);

	double const x0(-3.0);
	double const x1( 3.0);
	std::function<double(double)> const f([](double const &x) { return x * x * x; });

	BisectionMethod method(f);

	double const x(method(x0, x1));

	BOOST_REQUIRE_SMALL(x, EPSILON);
}

BOOST_AUTO_TEST_CASE(ComplexFunction)
{
	double const EPSILON(0.0001);

	double const x0(1.0);
	double const x1(4.0);
	std::function<double(double)> const f([](double const &x) { return std::pow(x, 4.0) - x - 10; });

	BisectionMethod method(f);

	double const x(method(x0, x1));

	BOOST_REQUIRE_CLOSE(1.85558452, x, EPSILON);
}

BOOST_AUTO_TEST_CASE(AnotherComplexFunction)
{
	double const EPSILON(0.0001);

	double const x0(0.2);
	double const x1(0.5);
	std::function<double(double)> const f([](double const &x) { return x * x * x - 7.0 * x + 2.0; });

	BisectionMethod method(f);

	double const x(method(x0, x1));

	BOOST_REQUIRE_CLOSE(0.28916854, x, EPSILON);
}

BOOST_AUTO_TEST_CASE(YetAnotherComplexFunction)
{
	double const EPSILON(0.0001);

	double const x0(-2.0);
	double const x1(3.0 / 4.0);
	std::function<double(double)> const f([](double const &x) { return (x * x * x + 2) / 7.0; });

	BisectionMethod method(f);

	double const x(method(x0, x1));

	BOOST_REQUIRE_CLOSE(-1.25992104, x, EPSILON);
}

BOOST_AUTO_TEST_SUITE_END()

